# Copyright 2015 ZhangZhaoyuan
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require 'time'
require 'uri'
require 'aliyunsdk/core/errors'
require 'json'
require 'rexml/document'
module Aliyunsdk
  module Core
    # API utilities
    module ApiUtil
      ADDRESS = {SLB: 'slb.aliyuncs.com', ECS: 'ecs.aliyuncs.com'}
      PROTOCOL_HTTP = 'http'
      PROTOCOL_HTTPS = 'https'

      HTTP_GET_METHOD = 'GET'
      HTTP_POST_METHOD = 'POST'

      # find api request address according to the api name
      # @param api_name [String] api name
      # @return address [String]
      def self.find_api_address(api_name)
        ApiUtil::ADDRESS[api_name] || 'unknown'
      end

      # Generate timestamp.
      # According ISO8601, and UTC. Format:YYYY-MM-DDThh:mm:ssZ
      # @return [String] timestamp
      def self.gen_timestamp
        Time.now.getutc.iso8601
      end

      # URL Encode
      # @param str [String]
      # @return [String]
      def self.percent_encode(str)
        percent_string = URI.encode_www_form_component str.to_s.strip
        percent_string.gsub('%7E', '~').gsub('+', '%20').gsub('*', '%2A')
      end

      # Parse response to a hash
      # @param res [String] response string
      # @param format [String]
      # @return [Hash]
      def self.parse_response(res, format)
        case format.upcase
          when 'XML'
            parse_from_xml res
          when 'JSON'
            parse_from_json res
          else
            raise ParseResException, "Unknown format! format=#{format.upcase}"
        end
      end

      # Makes an underscored, lowercase form from the expression in the string
      # @param camel_cased_word [String]
      def self.underscore(camel_cased_word)
        return camel_cased_word unless camel_cased_word =~ /[A-Z-]|::/
        word = camel_cased_word.to_s.gsub(/::/, '/')
        word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
        word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
        word.tr!("-", "_")
        word.downcase!
        word
      end

      private

      # Parse from xml format
      # @param res [String] response string
      def self.parse_from_xml(res)
        result = {}
        if res.is_a? REXML::Element
          doc = res
        else
          doc = REXML::Document.new(res).root
        end
        doc.elements.each do |element|
          if element.has_elements?
            if result.has_key? element.name
              result[element.name] = [result[element.name]] unless result[element.name].is_a? Array
              result[element.name] << parse_from_xml(element)
            else
              result[element.name] = parse_from_xml element
            end
          else
            if result.has_key? element.name
              result[element.name] = [result[element.name]] unless result[element.name].is_a? Array
              result[element.name] << element.text
            else
              result[element.name] = element.text
            end
          end
        end
        result
      end

      # Parse from json format
      # @param res [String] response string
      def self.parse_from_json(res)
        JSON.parse res
      end
    end
  end
end